package es.us.idinfor;

import java.util.List;
import java.util.Set;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import es.us.idinfor.util.InputFlow;

public class Sequences {
	private Set<Sequence> sequences;
	
	public Sequences() {
		sequences = Sets.newHashSet();
	}
	
	public Sequences(String filename) {
		sequences = Sets.newHashSet();
    	
    	Iterable<String> it1 = new InputFlow(filename);
		Iterable<Sequence> it2 = Iterables.transform(it1, Sequence.getExpression());
		
		for(Sequence s: it2) {
			add(s);
		}
	}
	
	public boolean add(Sequence s) {
		return sequences.add(s);
	}
	
	public Set<Window> getSimilarWindows() {
		Set<Window> res = Sets.newHashSet();
		int ini = 0;
		
		if(!sequences.isEmpty()) {
			ini = maximumCommonSize();
			
			while(res.isEmpty() && (ini > 0)) {
				res = getSimilarWindows(ini);
				ini--;
			}
		}
		
		return res;
	}
	
	public Set<Window> getSimilarWindows(int size) {
		Set<Window> res = Sets.newHashSet();
		
		if(!sequences.isEmpty()) {
			for(Sequence s: sequences) {
				if(res.isEmpty()) {
					res.addAll(s.windows("w", size));
				}
				else {
					res.retainAll(s.windows("w", size));
				}
			}
		}
		
		return res;
	}
	
	public List<Window> getSimilarWindows(Window w) {
		List<Window> res = Lists.newArrayList();
		Set<Window> aux = null;
		long time = 0;
		
		if(!sequences.isEmpty()) {
			for(Sequence s: sequences) {
				time = (w.getTimeStampEnd() - w.getTimeStampStart()) / 1000;
				aux = s.windows("w", (int) time);
				aux.retainAll(Sets.newHashSet(w));
				
				if(!aux.isEmpty()) {
					res.addAll(aux);
				}
			}
		}
		
		aux = null;
		
		return res;
	}
	
	public Window getMaximumSimilarWindow() {
		Window res = null;
		
		for(Window w: getSimilarWindows()) {
			if((res == null) || (res.size() < w.size())) {
				res = w;
			}
		}
		
		return res;
	}
	
	public Episode getMaximumEpisode(String name) {
		Episode res = new Episode(name);
		Window w = getMaximumSimilarWindow();
		List<Window> ws = getSimilarWindows(w);
		Set<Event> labels = Sets.newHashSet();
		Event act = null;
		
		for(int i = w.getEvents().size() - 1; i >= 0; i--) {
			labels.clear();
			
			for(Window aux: ws) {
				act = aux.getEvents().get(i);
				
				labels.add(act);
			}
			
			res.addParallelGroup(labels);
		}
		
		res.setWindows(ws);
		
		act = null;
		labels = null;
		ws = null;
		w = null;
		
		return res;
	}
	
	public int maximumCommonSize() {
		int res = 0;
		int aux = 0;
		
		if(!sequences.isEmpty()) {
			for(Sequence s: sequences) {
				aux = s.size();
				
				if((res == 0) || (res > aux)) {
					res = aux;
				}
			}
		}
		
		return res;
	}
}
